<?php


namespace app\library\create\lib;

use app\core\exception\ApiException;
use Exception;
use think\facade\Db;

/**
 * 获得数据库的字段详情
 * Class GetFields
 * @package app\library\create\lib
 */
class GetFields
{

    /**
     * 获得后面需要的数据库字段信息
     * @param $tableNames
     * @param $prefix
     * @return array
     * @throws ApiException
     */
    public static function index($tableNames, $prefix)
    {
        $self = new self();
        $tables = is_valid_array($tableNames) ?
            $self->getTables($tableNames, $prefix) :
            $tables = Db::query("show table status");
        return $self->getTableDetail($tables);
    }

    /**
     * @param $tableNames
     * @param $prefix
     * @return array
     * @throws ApiException
     */
    private function getTables($tableNames, $prefix)
    {
        $tables = [];
        foreach ($tableNames as $table) {
            $sql = "show table status like '$prefix$table'";
            $table = Db::query($sql);
            ($table[0] ?? false) || error("$table 不存在于数据库当中");
            $tables[] = $table[0];
        }

        return $tables;
    }

    /**
     * 获得数据库字段的详细
     * @param $tables
     * @return array
     * @throws ApiException
     * @throws Exception
     */
    public function getTableDetail($tables)
    {
        $tableFields = [];
        foreach ($tables as $table) {
            $tableName = $table['Name'] ?? error('表名错误,生成异常');
            $fields = Db::query("show full fields from  `" . $tableName . "`");
            $propertyArr = $this->getFiles($fields, $tableName); //获得属性的字段信息
            $tableFields[] = [
                'tableName' => $tableName,
                'fields' => $propertyArr,
                'comment' => $table['Comment'],
            ];
        }
        print_r($tableFields);
        exit;
        return $tableFields;

    }

    /**
     * 获得数据库的字段属性列表
     * @param $fields
     * @param $tableName
     * @return array
     * @throws ApiException
     */
    private function getFiles($fields, $tableName)
    {
        $filesArr = [];
        foreach ($fields as $field) {
            $fieldName = $field['Field'] ?? false || error("字段名字不存在");
            list($propertyType, $range) = $this->getType($field['Type'] ?? '', $field['Comment']);
            $filesArr[] = [
                'filed' => $fieldName,
                'type' => $propertyType,
                'canNull' => $field['Null'],
                'comment' => $field['Comment'],
                'range' => $range,
            ];
        }
        is_valid_array($filesArr) || error("$tableName 该表不存在字段");
        return $filesArr;
    }

    /**
     * 获得字段的数据类型
     * @param $type
     * @return array
     */
    private function getType($type, $comment)
    {
        $typeStr = 'string';
        $range = null;
        if (str_contains($type, 'int')) {
            if (str_contains($type, 'tinyint')) {
                $valueIn = $this->findStatus($comment);
                if (!$valueIn) {
                    //匹配status状态
                    if ($type == 'tinyint unsigned') {
                        $range['min'] = 0;
                        $range['max'] = 255;
                    } else {
                        $range['min'] = -128;
                        $range['max'] = 127;
                    }
                } else {
                    $range['valueIn'] = $valueIn;
                }
            }
            $typeStr = 'int';
        } elseif (str_contains($type, 'varchar')) {
            $typeStr = 'string';
            $range['len'] = $this->findNum($type);
        } elseif (str_contains('decimal', $type)) {
            $typeStr = 'float';
        }
        return [$typeStr, $range];
    }

    function findStatus($a)
    {
        preg_match_all('/\d+/', $a, $arr);
        return is_valid_array($arr[0] ?? null) ? $arr[0] : null;
    }

    function findNum($str = '')
    {
        $str = trim($str);
        if (empty($str)) {
            return '';
        }
        $result = '';
        for ($i = 0; $i < strlen($str); $i++) {
            if (is_numeric($str[$i])) {
                $result .= $str[$i];
            }
        }
        return $result;
    }
}